package com.iot08.api.service.supplement;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.iot08.api.config.redis.RedisClusterService;
import com.iot08.api.service.AccountService;
import com.iot08.api.service.WxgzConfigService;
import com.iot08.api.utils.buckettool.BaseBucketTool;
import com.iot08.api.utils.FileUtil;
import com.iot08.common.constant.CacheEnum;
import com.iot08.common.constant.Const;
import com.iot08.common.entity.app.Account;
import com.iot08.common.entity.app.Wxgzconfig;
import com.iot08.common.utils.HttpReq;
import com.iot08.common.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.TrustManager;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @version 1.0
 * @Description: 微信端相关业务处理
 * @time: 2020/11/12 18:32
 * @author: Rock
 */
@Slf4j
@Service
public class WeixinService {

    @Resource
    private WxgzConfigService wxgzConfigService;
    @Resource
    private AccountService accountService;
    @Resource
    private BaseBucketTool baseBucketTool;

    @Value("${wxgz.appId}")
    private String wxgzAppId;
    @Value("${wxgz.appSecret}")
    private String wxgzAppSecret;

    //微信相关请求接口返回成功码
    private static final Integer ERRCODE0 = 0;

    private static final String FILE_PATH = "/tmp/";

    /**
     * @param wxgzMasterId
     * @time: 2021/1/8 16:13
     * @author: Rock
     * @version 1.0
     */
    public String getAccessToken(String wxgzMasterId) {
        if (StringUtil.isBlank(wxgzMasterId)) {
            return null;
        }
        String accessToken = RedisClusterService.getJedisCluster().get(wxgzMasterId + CacheEnum.WACHAT_ACCESS_TOKEN.getKey());
        if (StringUtil.isBlank(accessToken)) {
            //默认是这个,然后找数据库中的配置
            String appId = wxgzAppId;
            String appSecret = wxgzAppSecret;
            Wxgzconfig wxgzconfig = wxgzConfigService.findById(wxgzMasterId);
            if (wxgzconfig != null) {
                appId = wxgzconfig.getAppid();
                appSecret = wxgzconfig.getAppsecret();
            }
            String url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", appId, appSecret);
            String data = HttpReq.sendGet(url, null);
            log.info("获取token返回结果:{}", data);
            if (StringUtil.isNotBlank(data)) {
                JSONObject json = JSON.parseObject(data);
                if (json != null && StringUtil.isNotBlank(json.getString("access_token"))) {
                    accessToken = json.getString("access_token");
                    RedisClusterService.getJedisCluster().setex(wxgzMasterId + CacheEnum.WACHAT_ACCESS_TOKEN.getKey(), CacheEnum.WACHAT_ACCESS_TOKEN.getExpire(), accessToken);
                } else {
                    log.info("access_token is null.");
                }
            }
        }
        return accessToken;
    }

    /**
     * 发送微信推送
     *
     * @param type
     * @param content
     * @time: 2020/11/13 10:18
     * @author: Rock
     * @version 1.0
     */
    public boolean replyWxMsg(int type, String content, String wxgzMasterId, String wxid) {
        if (content == null || content.length() == 0){
            return false;
        }

        String accessToken = getAccessToken(wxgzMasterId);
        if (StringUtil.isBlank(accessToken)) {
            log.error("accessToken is null. wxgzMasterId={}", wxgzMasterId);
            return false;
        }
        String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + accessToken;
        JSONObject param = new JSONObject();
        JSONObject sub = new JSONObject();
        param.put("touser", wxid);
        if (type == 1) {
            param.put("msgtype", "text");
            param.put("text", sub);
            sub.put("content", content);
        } else if (type == 2) {
            ByteArrayOutputStream outputStream = null;
            if (content.startsWith("/root")) {
                //获取本地图片
                outputStream = FileUtil.getFileByte(content);
            } else {
                //从阿里云下载文件
                outputStream = baseBucketTool.downloadFileStream(BaseBucketTool.MESSAGE_COMMON_PATH + content);
            }
            if (outputStream == null) {
                log.error("获取图片失败。 path = {}", content);
                return false;
            }
            String msgtype = "image";
            //把文件上传到微信素材
            String mediaId = uploadFile(outputStream, content, msgtype, accessToken);
            if (StringUtil.isNotBlank(mediaId)) {
                param.put("msgtype", msgtype);
                sub.put("media_id", mediaId);
                param.put("image", sub);
            } else {
                log.error("微信公众号推送失败，上传图片不成功。");
                return false;
            }
        } else if (type == 3) {
            //从阿里云下载文件
            ByteArrayOutputStream outputStream = baseBucketTool.downloadFileStream(BaseBucketTool.MESSAGE_COMMON_PATH + content);
            if (outputStream == null) {
                log.error("下载阿里云语音失败。 path = {}", BaseBucketTool.MESSAGE_COMMON_PATH + content);
                return false;
            }
            String msgtype = "voice";
            //把文件上传到微信素材
            String mediaId = uploadFile(outputStream, content, msgtype, accessToken);
            if (StringUtil.isNotBlank(mediaId)) {
                param.put("msgtype", msgtype);
                sub.put("media_id", mediaId);
                param.put("voice", sub);
            } else {
                log.error("微信公众号推送失败，上传语音不成功。");
                return false;
            }
        } else {
            log.error("replyWxMsg exception. type = {}, wxid={}", type, wxid);
            return false;
        }
        String res = HttpReq.sendPostJson(url, param.toJSONString());
        if (StringUtil.isNotBlank(res)) {
            JSONObject data = JSON.parseObject(res);
            if (data != null && ERRCODE0.equals(data.getInteger("errcode"))) {
                log.info("微信公众号推送成功，content={}.  res={}", param, res);
                return true;
            }
        }
        log.warn("微信公众号推送失败,返回结果={}", res);
        return false;
    }

    /**
     * 获取微信后台创建的用户标签
     *
     * @param wxgzMasterId
     * @time: 2021/1/8 17:35
     * @author: Rock
     * @version 1.0
     */
    public int getNewestTagsId(String wxgzMasterId) {
        int id = 0;
        String url = "https://api.weixin.qq.com/cgi-bin/tags/get?access_token=" + getAccessToken(wxgzMasterId);
        String res = HttpReq.sendGet(url, null);
        if (StringUtil.isNotBlank(res)) {
            JSONObject data = JSONObject.parseObject(res);
            if (data != null && ERRCODE0.equals(data.getInteger("errcode"))) {
                JSONArray jsonArray = data.getJSONArray("tags");
                if (jsonArray != null) {
                    for (int i = 0; i < jsonArray.size(); i++) {
                        Integer tagId = jsonArray.getJSONObject(i).getInteger("id");
                        if (tagId != null && id < tagId) {
                            id = tagId;
                        }
                    }
                }
            }
        }
        log.error("获取微信后台创建的用户标签失败={}", res);
        return id;
    }

    /**
     * 设置用户标签
     *
     * @param wxid
     * @param wxgzMasterId
     * @time: 2020/11/13 10:56
     * @author: Rock
     * @version 1.0
     */
    public void setMemberTags(String wxid, String wxgzMasterId) {
        //获取近一个最新的用户标签id
        int tagId = 0;
        String url = "https://api.weixin.qq.com/cgi-bin/tags/get?access_token=" + getAccessToken(wxgzMasterId);
        String res = HttpReq.sendGet(url, null);
        if (StringUtil.isNotBlank(res)) {
            JSONObject data = JSONObject.parseObject(res);
            if (data != null && data.get("tags") instanceof JSONArray) {
                JSONArray jsonArray = data.getJSONArray("tags");
                for (int i = 0; i < jsonArray.size(); i++) {
                    Integer id = jsonArray.getJSONObject(i).getInteger("id");
                    if (id != null && tagId < id) {
                        tagId = id;
                    }
                }
            }
        }
        url = "https://api.weixin.qq.com/cgi-bin/tags/members/batchtagging?access_token=" + getAccessToken(wxgzMasterId);
        JSONObject param = new JSONObject();
        param.put("tagid", tagId);
        List<String> openidList = new ArrayList<>();
        openidList.add(wxid);
        param.put("openid_list", openidList);
        res = HttpReq.sendPostJson(url, param.toJSONString());
        if (StringUtil.isNotBlank(res)) {
            JSONObject data = JSONObject.parseObject(res);
            if (data != null && Const.INT_0.equals(data.getInteger("errcode"))) {
                log.info("设置用户标签成功");
                return;
            }
        }
        log.error("设置用户标签失败, res={}; param={}", res, param.toJSONString());
    }

    /**
     * @param outputStream
     * @param fileName
     * @param type
     * @param token
     * @time: 2021/3/22 16:59
     * @author: Rock
     * @version 1.0
     */
    public static String uploadFile(ByteArrayOutputStream outputStream, String fileName, String type, String token) {
        try {
            //上传素材
            String path = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=" + token + "&type=" + type;
            String result = connectHttpsByPost(path, fileName, outputStream);
            result = result.replaceAll("[\\\\]", "");
            log.info("result: " + result);
            JSONObject resultJSON = JSONObject.parseObject(result);
            if (resultJSON != null) {
                if (StringUtil.isNotBlank(resultJSON.get("media_id"))) {
                    log.info("上传{}素材成功", type);
                    return resultJSON.getString("media_id");
                } else {
                    log.error("上传{}素材失败", type);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param path
     * @param fileName
     * @param outputStream
     * @time: 2021/3/22 16:53
     * @author: Rock
     * @version 1.0
     */
    public static String connectHttpsByPost(String path, String fileName, ByteArrayOutputStream outputStream) throws Exception {
        URL urlObj = new URL(path);
        //连接
        HttpURLConnection con = (HttpURLConnection) urlObj.openConnection();
        String result = null;
        con.setDoInput(true);

        con.setDoOutput(true);

        con.setUseCaches(false); // post方式不能使用缓存

        // 设置请求头信息
        con.setRequestProperty("Connection", "Keep-Alive");
        con.setRequestProperty("Charset", "UTF-8");
        // 设置边界
        String BOUNDARY = "----------" + System.currentTimeMillis();
        con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);

        // 请求正文信息
        // 第一部分：
        StringBuilder sb = new StringBuilder();
        sb.append("--"); // 必须多两道线
        sb.append(BOUNDARY);
        sb.append("\r\n");
        sb.append("Content-Disposition: form-data;name=\"media\";filelength=\"" + outputStream.size() + "\";filename=\""

                + fileName + "\"\r\n");
        sb.append("Content-Type:application/octet-stream\r\n\r\n");
        byte[] head = sb.toString().getBytes("utf-8");
        // 获得输出流
        OutputStream out = new DataOutputStream(con.getOutputStream());
        // 输出表头
        out.write(head);

        // 文件正文部分
        // 把文件已流文件的方式 推入到url中
        DataInputStream in = new DataInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
        int bytes = 0;
        byte[] bufferOut = new byte[1024];
        while ((bytes = in.read(bufferOut)) != -1) {
            out.write(bufferOut, 0, bytes);
        }
        in.close();
        // 结尾部分
        byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定义最后数据分隔线
        out.write(foot);
        out.flush();
        out.close();
        StringBuffer buffer = new StringBuffer();
        BufferedReader reader = null;
        try {
            // 定义BufferedReader输入流来读取URL的响应
            reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            if (result == null) {
                result = buffer.toString();
            }
        } catch (IOException e) {
            System.out.println("发送POST请求出现异常！" + e);
            e.printStackTrace();
        } finally {
            if (reader != null) {
                reader.close();
            }
        }
        return result;
    }

    /**
     * @param wxgzMasterId
     * @param appId
     * @time: 2021/5/10 10:51
     * @author: Rock
     * @version 1.0
     */
    public String getTicket(String wxgzMasterId, String appId) {
        String ticket = RedisClusterService.getJedisCluster().get(appId + CacheEnum.WACHAT_TICKET.getKey());
        if (StringUtil.isBlank(ticket)) {
            //ticket过期，重新从微信获取并存入redis
            String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=" + getAccessToken(wxgzMasterId);
            String data = HttpReq.sendGet(url, null);
            log.info("获取token返回结果:{}", data);
            if (StringUtil.isNotBlank(data)) {
                JSONObject json = JSON.parseObject(data);
                if (json != null && StringUtil.isNotBlank(json.getString("ticket"))) {
                    ticket = json.getString("ticket");
                    RedisClusterService.getJedisCluster().setex(appId + CacheEnum.WACHAT_TICKET.getKey(), CacheEnum.WACHAT_TICKET.getExpire(), ticket);
                } else {
                    log.info("access_token is null.");
                }
            }
        }
        return ticket;
    }

    /**
     * @param wxgzMasterId
     * @param mediaId
     * @param type
     * @time: 2021/5/11 15:29
     * @author: Rock
     * @version 1.0
     */
    public JSONObject getTemporaryMateria(String wxgzMasterId, String mediaId, String type) {
        JSONObject resultJSONObject = new JSONObject();
        BufferedOutputStream bufferedOutputStream = null;
        FileOutputStream fileOutputStream = null;
        try {
            String path = "";
            if ("voice".equals(type)) {
                path = FILE_PATH + mediaId + ".amr";
            } else {
                path = FILE_PATH + mediaId + ".jpg";
            }
            String url = "https://api.weixin.qq.com/cgi-bin/media/get?media_id=" + mediaId + "&access_token=" + getAccessToken(wxgzMasterId);
            File file = httpRequestToFile(path, url);
            if (file == null) {
                resultJSONObject.put("msg", "文件下载失败");
                return resultJSONObject;
            }
            resultJSONObject.put("url", path);
            if ("voice".equals(type)) {
                resultJSONObject.put("duration", FileUtil.getAmrDuration(file));
            }
        } catch (Exception e) {
            log.error(" EXCEPTION = {}", e.getMessage());
            resultJSONObject.put("msg", "程序异常");
            return resultJSONObject;
        } finally {
            try {
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
                if (bufferedOutputStream != null) {
                    bufferedOutputStream.close();
                }
            } catch (Exception e) {
                log.error(" Stream close is exception = {}", e.getMessage());

            }
        }
        resultJSONObject.put("msg", "获取成功");
        return resultJSONObject;
    }

    /**
     * 获取微信的用户昵称
     * @param openid
     * @param masterId
     * @time: 2021/6/9 9:46
     * @author: Rock
     * @version 1.0
     */
    public String getWxUserName(String openid, String masterId) {

        JSONObject wxUserInfo = this.getWxUserInfo(openid, masterId);
        String nickname = wxUserInfo.getString("nickname");
        if (nickname == null) {
            return "微信公众绑定";
        }
        return nickname;
    }

    /**
     * 获取微信用户信息
     * @parm openid
     * @param masterId
     * @time: 4/8/22 6:14 PM
     * @author: Weichao
     * @version 1.0
     */
    public JSONObject getWxUserInfo(String openid, String masterId) {
        String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="
                + getAccessToken(masterId) + "&openid=" + openid;
        String data = HttpReq.sendGet(url, null);
        log.info("获取getWxUserInfo返回结果:{}", data);
        return JSONObject.parseObject(data);
    }


    public static File httpRequestToFile(String fileName, String url) {
        if (fileName == null || url == null) {
            return null;
        }
        File file = null;
        HttpURLConnection conn = null;
        InputStream inputStream = null;
        FileOutputStream fileOut = null;
        try {
            URL u = new URL(url);
            conn = (HttpURLConnection) u.openConnection();
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestMethod("GET");
            inputStream = conn.getInputStream();
            if (inputStream != null) {
                file = new File(fileName);
                if (!file.getParentFile().exists()) {
                    file.getParentFile().mkdirs();
                }
            } else {
                return null;
            }

            //写入到文件
            fileOut = new FileOutputStream(file);
            if (fileOut != null) {
                int c = inputStream.read();
                while (c != -1) {
                    fileOut.write(c);
                    c = inputStream.read();
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            if (conn != null) {
                conn.disconnect();
            }

            /*
             * 必须关闭文件流
             * 否则JDK运行时，文件被占用其他进程无法访问
             */
            try {
                inputStream.close();
                fileOut.close();
            } catch (IOException execption) {
                log.error(execption.getMessage());
            }
        }
        return file;
    }


}
